// Ensure ThreeJS is in global scope for the 'examples/'
global.THREE = require("three");

// Include any additional ThreeJS examples below
require("three/examples/js/controls/OrbitControls");

const canvasSketch = require("canvas-sketch");
const glslify = require('glslify');

const settings = {
  animate: true, // Make the loop animated
  context: "webgl", // Get a WebGL canvas rather than 2D
};

const sketch = ({ context }) => {
  // Create a renderer
  const renderer = new THREE.WebGLRenderer({
    canvas: context.canvas
  });

  // WebGL background color
  renderer.setClearColor("#fff", 1);

  // Setup a camera
  const camera = new THREE.PerspectiveCamera(50, 1, 0.01, 100);
  camera.position.set(0, 0, -4);
  camera.lookAt(new THREE.Vector3());

  // Setup camera controller
  const controls = new THREE.OrbitControls(camera, context.canvas);

  // Setup your scene
  const scene = new THREE.Scene();

  // Setup a geometry
  const geometry = new THREE.BoxGeometry(1.5, 1.5, 1.5);

  const vertexShaderSource = glslify(/* glsl */`
    varying vec2 vUv;
    varying vec3 vPosition;

    void main() {
      vUv = uv;
      vPosition = position;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `)

  // 来个所有的噪声测试
  const fragmentShaderSource = glslify(/* glsl */`
    #pragma glslify: snoise2 = require('glsl-noise/simplex/2d');
    #pragma glslify: snoise3 = require('glsl-noise/simplex/3d');
    #pragma glslify: snoise4 = require('glsl-noise/simplex/4d');
    #pragma glslify: cnoise2 = require('glsl-noise/classic/2d');
    #pragma glslify: cnoise3 = require('glsl-noise/classic/3d');
    #pragma glslify: cnoise4 = require('glsl-noise/classic/4d');
    #pragma glslify: pnoise2 = require('glsl-noise/periodic/2d');
    #pragma glslify: pnoise3 = require('glsl-noise/periodic/3d');
    #pragma glslify: pnoise4 = require('glsl-noise/periodic/4d');
    
    varying vec2 vUv;
    varying vec3 vPosition;

    uniform float time;

    void main() {
      // float noiseRes = snoise2(vUv.xy);
      // float noiseRes = cnoise2(vUv.xy * 10.0);
      float noiseRes = 2.3 * pnoise2(10.0 * vec2(vUv.x + sin(time), vUv.y), vec2(100.0));
      
      vec4 glFragColor = vec4(vec3(0.0) + noiseRes, 1.0);
      gl_FragColor = glFragColor;
    }
  `);

  // Setup a material
  const material = new THREE.ShaderMaterial({
    transparent: true,
    uniforms: {
      time: { value: 0.0 }
    },
    vertexShader: vertexShaderSource,
    fragmentShader: fragmentShaderSource
  });

  // Setup a mesh with geometry + material
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  // draw each frame
  return {
    // Handle resize events here
    resize({ pixelRatio, viewportWidth, viewportHeight }) {
      renderer.setPixelRatio(pixelRatio);
      renderer.setSize(viewportWidth, viewportHeight, false);
      camera.aspect = viewportWidth / viewportHeight;
      camera.updateProjectionMatrix();
    },
    // Update & render your scene here
    render({ time }) {
      material.uniforms.time.value = time
      controls.update();
      renderer.render(scene, camera);
    },
    // Dispose of events & renderer for cleaner hot-reloading
    unload() {
      controls.dispose();
      renderer.dispose();
    }
  };
};

canvasSketch(sketch, settings);

